package vn.org.hcmut.or.processing;

import java.util.ArrayList;
import java.util.Hashtable;

import vn.org.hcmut.or.model.AvailableJob;
import vn.org.hcmut.or.model.AvailableWindow;
import vn.org.hcmut.or.model.FragmentJob;
import vn.org.hcmut.or.model.RemainDuration;
import vn.org.hcmut.or.model.SchedulingInfo;
import vn.org.hcmut.or.test.ParserTest;


public class ScheduleProcessing {
	SchedulingInfo schedulingInfo;
	ParserTest parserTest = new ParserTest();
	public ScheduleProcessing()
	{

	}

	public void arrangeJobToAvaiableWindow(SchedulingInfo schedulingInfo)
	{
		/*for(int i=0;i<schedulingInfo.getNumOfJob();i++)
		{
			AvailableJob aj = schedulingInfo.getaJob().get(i);
			if(checkFitJobInwindow(aj,schedulingInfo.getHashTableWindow()) == true && !aj.isProAllWindows())
			{
				if(handleFitJob(aj,schedulingInfo.getHashTableWindow()) == false)
					i--;
			}
			else if(checkFitJobInwindow(aj,schedulingInfo.getHashTableWindow()) == true && aj.isProAllWindows())
			{
				System.out.println("Job "+aj.getIdJob()+ " fit but no window to place");
				aj.setProAllWindow(false);
				if(!aj.isFragment())
				{
					System.out.println("Job "+aj.getIdJob()+ " fit but no window to place and no fragment");
					handleUnfragmentJob(aj,schedulingInfo.getaWindow(),schedulingInfo.getMinsplit());
				}
				else
				{
					System.out.println("Job "+aj.getIdJob()+ " fit but no window to place and fragment");
					handleFragmentJob(aj, schedulingInfo);
				}
			}
			else if(!aj.isFragment())
			{
				handleUnfragmentJob(aj,schedulingInfo.getaWindow(),schedulingInfo.getMinsplit());
			}
			else if(aj.isFragment())
			{
				handleFragmentJob(aj, schedulingInfo);
			}
		}*/
		// Pharse 1 : Handle fit job :
		System.out.println("+++++++++++++++++++++++ Start Pharse 1 : Handle fit job ++++++++++++++++++++++++++++");
		for(int i=0;i<schedulingInfo.getNumOfJob();i++)
		{
			
			AvailableJob aj = schedulingInfo.getaJob().get(i);
			System.out.println("Handle fit Job "+aj.getIdJob());
			if(!aj.isProcess() && checkFitJobInwindow(aj,schedulingInfo.getHashTableWindow()) == true)
			{
				if(handleFitJob(aj,schedulingInfo.getHashTableWindow()) == false){
					continue;
				}	
			}
		}
		System.out.println("+++++++++++++++++++++++ End Pharse 1 : Handle fit job ++++++++++++++++++++++++++++");
		parserTest.printWindowAndRemainDuration(schedulingInfo);
		//parserTest.printJobAndWindow(schedulingInfo);
		System.out.println("+++++++++++++++++++++++ start Pharse 2 :Handle unfragment job++++++++++++++++++++++++++++");
		//Pharse 2 : Handle unfragment job
		
		for(int i=0;i<schedulingInfo.getNumOfJob();i++)
		{
			
			AvailableJob aj = schedulingInfo.getaJob().get(i);
			System.out.println("Handle unfragment for job "+aj.getIdJob() +" with status ="+aj.isProcess());
			if(aj.isProcess() && !aj.isTemporyFit())
				continue;
			if(checkFitJobInwindow(aj,schedulingInfo.getHashTableWindow()) == true && aj.isProcess())
			{
					System.out.println("Job "+aj.getIdJob()+ " fit but no window to place");
					aj.setProAllWindow(false);
					if(!aj.isFragment())
					{
						System.out.println("Job "+aj.getIdJob()+ " fit but no window to place and no fragment");
						handleUnfragmentJob(aj,schedulingInfo.getaWindow(),schedulingInfo.getMinsplit());
					}
					else
					{
						continue;
					}
			}
			else if(!aj.isProcess()&&!aj.isFragment())
			{
				handleUnfragmentJob(aj,schedulingInfo.getaWindow(),schedulingInfo.getMinsplit());
			}
		}
		System.out.println("+++++++++++++++++++++++ End Pharse 2 :Handle unfragment job++++++++++++++++++++++++++++");
		parserTest.printWindowAndRemainDuration(schedulingInfo);
		
		System.out.println("+++++++++++++++++++++++ Start Pharse 3 :Handle fragment job++++++++++++++++++++++++++++");
		for(int i=0;i<schedulingInfo.getNumOfJob();i++)
		{
			AvailableJob aj = schedulingInfo.getaJob().get(i);
			if(aj.isProcess())
				continue;
			if(aj.isFragment())
			{
				schedulingInfo.buildAavaibleWindowHashTable();
				handleFragmentJob(aj, schedulingInfo);
				System.out.println("End handle for FragmentJob "+aj.getIdJob());
				parserTest.printWindowAndRemainDuration(schedulingInfo);
			}
		}
		System.out.println("+++++++++++++++++++++++ End Pharse 3 :Handle fragment job++++++++++++++++++++++++++++");
		parserTest.printJobAndWindow(schedulingInfo);
		
	}
	public boolean handleFitJob(AvailableJob aj,Hashtable<Integer, ArrayList<AvailableWindow>> hashTableWindow)
	{
		boolean result = false;
		ArrayList<AvailableWindow> law = hashTableWindow.get(aj.getProTimeJob());
		if(law.size() > 0){
			AvailableWindow aw = law.get(0);
			aj.setDurationJobInWindow(aw.getId(), aj.getProTimeJob());
			System.out.println("Fit Job "+aj.getIdJob() +" located in "+aw.getId());
			law.remove(aw);
			hashTableWindow.remove(aj.getProTimeJob());
			hashTableWindow.put(aj.getProTimeJob(), law);
			aj.setProAllWindow(true);
			aw.setProcess(true);
			result = true;
			System.out.println("Avaiable Window "+aw.getId()+" is fully occupied by Job "+aj.getIdJob());
		}
		else
		{
			aj.setProAllWindow(true);
			aj.setTemporyFit(true);
			System.out.println("There isn't Avaiable Window with duration "+aj.getProTimeJob()+ " is full for Job "+aj.getIdJob());
		}
		return result;
	}
	
	public RemainDuration getMinRemainDuration (ArrayList<RemainDuration>listRemainDuration){
		// can lay ra phan tu co duration nho nhat trong listRemainDuration 
		
//		int value = listRemainDuration.get(0).getDuration();
//		int pos = 0;
//		for (int index = 1; index<listRemainDuration.size();index++){
//		 int temp = listRemainDuration.get(index).getDuration();
//		 if (value > temp){
//		  value = temp;
//		  pos = index;
//		 }
//		}
//		return listRemainDuration.get(pos);
		
		RemainDuration remainDuration = listRemainDuration.get(0);
		for (int index = 1; index<listRemainDuration.size();index++){
			RemainDuration rmi = listRemainDuration.get(index);
			if (remainDuration.getDuration() > rmi.getDuration()){
				remainDuration = rmi;
			}	 
		}
		return remainDuration;

	}
	
	public void handleUnfragmentJob(AvailableJob aj,ArrayList<AvailableWindow>law,int minSplit)
	{
		// add tuan tu ,tim window phu hop nhat de add vao , cap nhat danh sach window neu window full hoac duoc chen them manh
		//int min = 
		// xet hieu awi.duratio - aj.getProcessingTime
		System.out.println("Handle Unfragment Job "+aj.getIdJob());
		ArrayList<RemainDuration> listRemainDuration= new ArrayList<RemainDuration>();
		for(int i = 0;i<law.size();i++)
		{
			AvailableWindow awi = law.get(i);
			if(awi.isProcess()){
				System.out.println("Window "+awi.getId() +" is already processed");
				continue;
			}
			else{
				int duration =  awi.getT_duration() -awi.getDurationWinCurrent() - aj.getProTimeJob();
				if(duration > 0){
					RemainDuration remainDuration = new RemainDuration(awi.getId(),duration);
					listRemainDuration.add(remainDuration);	
				}
			}
		};
		parserTest.printRemainDuration(listRemainDuration);
		RemainDuration minRmainDuration = getMinRemainDuration(listRemainDuration);
		if(minRmainDuration.getDuration() < minSplit)
		{
			System.out.println("Job "+aj.getIdJob() +" < minSplit");
			aj.setDurationJobInWindow(minRmainDuration.getId(), aj.getProTimeJob());
			System.out.println("Job "+aj.getIdJob() +" located in "+minRmainDuration.getId());
			aj.setProAllWindow(true);
			AvailableWindow aw = law.get(minRmainDuration.getId());
			law.get(minRmainDuration.getId()).setDurationWinCurrent(aj.getProTimeJob());
			law.get(minRmainDuration.getId()).setProcess(true);
			aw.setProcess(true);
			System.out.println(law.get(minRmainDuration.getId()).isProcess());
		}
		else
		{
			// truong hop minRmainDuration.getDuration() > minSplit
			//can cap nhat duration
			System.out.println("Job "+aj.getIdJob() +" > minSplit");
			System.out.println("minRmainDuration.getId() = "+minRmainDuration.getId());
			System.out.println("minRmainDuration.getDuration() = "+minRmainDuration.getDuration());
			aj.setDurationJobInWindow(minRmainDuration.getId(), aj.getProTimeJob());
			System.out.println("Job "+aj.getIdJob() +" located in "+minRmainDuration.getId());
			AvailableWindow aw = law.get(minRmainDuration.getId());
			aw.setDurationWinCurrent(aj.getProTimeJob());
			aj.setProAllWindow(true);
			if(aw.getT_duration() - aw.getDurationWinCurrent() < minSplit)
			{
				aw.setProcess(true);
			}
			
		}

	}
	public void handleFragmentJob(AvailableJob aj,SchedulingInfo schedulingInfo)
	{
		//xet truong hop fit theo tung level cua cac manh trong job
		/*
		can build lai Hash table window vi luc nay co the window da bi phan manh do 2 truong hop tren
		Xet 2 truong hop 
		-Fit:
			cap nhat vao window luon
		-KHong fit
			-Xu ly giong case 2 nhung phai cap nhat lai hash table window moi lan xet job moi
		*/
		ArrayList<FragmentJob> lfj = aj.getListFragJob();
		if(lfj == null ||lfj.size() == 0)
			return;
		/*for(int i = 0;i<lfj.size();i++)
		{
			FragmentJob fj = lfj.get(i);
			if(fj.isStatus())
			{
				System.out.println("Fragment is already processed");
				continue;
			}
			schedulingInfo.buildAavaibleWindowHashTable();

			if(checkFitFragmentJobInwindow(fj,schedulingInfo.getHashTableWindow()) == true && !fj.isStatus())
			{
				if(handleFitFragmentOfJob(aj,fj,schedulingInfo.getHashTableWindow()) == false)
				{
					i--;
				}
				
			}
			else if(checkFitFragmentJobInwindow(fj,schedulingInfo.getHashTableWindow()) == true && fj.isStatus())
			{
				fj.setStatus(false);
				handleUnfragmentOfJob(aj,fj,schedulingInfo.getaWindow(),schedulingInfo.getMinsplit());
				
			}
			else
			{
				//schedulingInfo.buildAavaibleWindowHashTable();
				handleUnfragmentOfJob(aj,fj,schedulingInfo.getaWindow(),schedulingInfo.getMinsplit());
			}
		}*/
		System.out.println("-----------------Handle fragment fo job "+aj.getIdJob()+"---------------------");
		for(int i = 0;i<lfj.size();i++)
		{
			
			FragmentJob fj = lfj.get(i);
			System.out.println("Handle fragment "+fj.getOrder() +"of Job "+fj.getId());
			if(fj.isStatus())
			{
				System.out.println("Fragment "+fj.getOrder() +" of job "+fj.getId()  +" is already processed");
				continue;
			}

			if(checkFitFragmentJobInwindow(fj,schedulingInfo.getHashTableWindow()) == true && !fj.isStatus())
			{
				if(handleFitFragmentOfJob(aj,fj,schedulingInfo.getHashTableWindow()) == false)
				{
					continue;
				}
				
			}
			
		}
		for(int i = 0;i<lfj.size();i++)
		{
			FragmentJob fj = lfj.get(i);
			if(fj.isStatus()&& !fj.isTemporyFit())
			{
				System.out.println("Fragment "+fj.getOrder() +" of job "+fj.getId()  +" is already processed");
				continue;
			}
			schedulingInfo.buildAavaibleWindowHashTable();

			if(checkFitFragmentJobInwindow(fj,schedulingInfo.getHashTableWindow()) == true && fj.isStatus())
			{
				fj.setStatus(false);
				handleUnfragmentOfJob(aj,fj,schedulingInfo.getaWindow(),schedulingInfo.getMinsplit());
				
			}
			else
			{
				handleUnfragmentOfJob(aj,fj,schedulingInfo.getaWindow(),schedulingInfo.getMinsplit());
			}
		}
		aj.setProAllWindow(true);
	}
	public boolean handleFitFragmentOfJob(AvailableJob aj,FragmentJob fj,Hashtable<Integer, ArrayList<AvailableWindow>> hashTableWindow)
	{
		boolean result = false;
		ArrayList<AvailableWindow> law = hashTableWindow.get(fj.getProcessingTime());
		if(law.size() > 0){
			AvailableWindow aw = law.get(0);
			aj.setDurationJobInWindow(aw.getId(), fj.getProcessingTime());
			law.remove(aw);
			hashTableWindow.remove(fj.getProcessingTime());
			hashTableWindow.put(fj.getProcessingTime(), law);
			fj.setStatus(true);
			aw.setProcess(true);
			result = true;
			System.out.println("Avaiable Window "+aw.getId()+" is fully occupied by fragment "+fj.getOrder()+" of Job "+fj.getId()+" with processing time = "+fj.getProcessingTime());
		}
		else
		{
			//aj.setProAllWindow(true);
			fj.setStatus(true);
			fj.setTemporyFit(true);
			System.out.println("There isn't Avaiable Window with duration "+fj.getProcessingTime()+ " is full for fragment "+fj.getOrder()+" of Job "+fj.getId());
		}
		return result;
	}
	boolean checkFitJobInwindow(AvailableJob aj,Hashtable<Integer, ArrayList<AvailableWindow>> hashTableWindow)
	{
		boolean result = false;
		if(hashTableWindow.containsKey(aj.getProTimeJob()))
		{
			//System.out.println("Window fit with job "+aj.getId());
			result = true;
			
		}
		return result;
	}
	boolean checkFitFragmentJobInwindow(FragmentJob fj,Hashtable<Integer, ArrayList<AvailableWindow>> hashTableWindow)
	{
		boolean result = false;
		if(hashTableWindow.containsKey(fj.getProcessingTime()))
		{
			//System.out.println("Window fit with job "+aj.getId());
			result = true;
			
		}
		return result;
	}
	public void handleUnfragmentOfJob(AvailableJob aj,FragmentJob fj,ArrayList<AvailableWindow>law,int minSplit)
	{

		System.out.println("--Handle Unfragment "+fj.getOrder()+" of Job "+fj.getId() +" with processing time = "+fj.getProcessingTime());
		ArrayList<RemainDuration> listRemainDuration= new ArrayList<RemainDuration>();
		for(int i = 0;i<law.size();i++)
		{
			AvailableWindow awi = law.get(i);
			if(awi.isProcess()){
				System.out.println("Window "+awi.getId() +"for fragment of Job "+fj.getId()+" with processing time "+fj.getProcessingTime()+" is already processed");
				continue;
			}
			else{
				int duration =  awi.getT_duration() - awi.getDurationWinCurrent() - fj.getProcessingTime();
				if(duration > 0){
					RemainDuration remainDuration = new RemainDuration(awi.getId(),duration);
					listRemainDuration.add(remainDuration);	
				}
				else
				{
					continue;
				}
			}
		}
		RemainDuration minRmainDuration = getMinRemainDuration(listRemainDuration);
		parserTest.printRemainDuration(listRemainDuration);
		if(minRmainDuration.getDuration() < minSplit)
		{
			System.out.println("Handle Unfragment of Job "+fj.getId() +" with processing time = "+fj.getProcessingTime() +" < minSplit");
			aj.setDurationJobInWindow(minRmainDuration.getId(), fj.getProcessingTime());
			System.out.println("Fragment "+fj.getOrder()+" job "+fj.getId() +" locate in window "+minRmainDuration.getId());
	//		aj.setProAllWindow(true);
			fj.setStatus(true);
			AvailableWindow aw = law.get(minRmainDuration.getId());
			aw.setProcess(true);
		}
		else
		{
			// truong hop minRmainDuration.getDuration() > minSplit
			//can cap nhat duration

			System.out.println("Handle Unfragment of Job "+fj.getId() +" with processing time = "+fj.getProcessingTime() +" > minSplit");
			System.out.println("minRmainDuration.getId() = "+minRmainDuration.getId());
			System.out.println("minRmainDuration.getDuration() = "+minRmainDuration.getDuration());
			
			aj.setDurationJobInWindow(minRmainDuration.getId(), fj.getProcessingTime());
			System.out.println("Fragment "+fj.getOrder()+" job "+fj.getId() +" locate in window "+minRmainDuration.getId());
			AvailableWindow aw = law.get(minRmainDuration.getId());
			law.get(minRmainDuration.getId()).setDurationWinCurrent(aw.getDurationWinCurrent()+fj.getProcessingTime());
			fj.setStatus(true);
			if(aw.getT_duration() - aw.getDurationWinCurrent() < minSplit)
			{
				aw.setProcess(true);
			}
	//		aj.setProAllWindow(true);
			
		}

	}
}
